﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ScopePropertyMetadata.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Windows
{
    using System.Windows;

    /// <summary>
    /// Defines the behavior aspects of a scope property.
    /// </summary>
    /// <remarks>
    /// Unfortunetly it is quite difficult to create an API for scope properties that is consistent with the 
    /// patterns used when using normal dependency properties. This is mainly due to a issue in Silverlight 
    /// where the <see cref="DependencyProperty.GetMetadata"/> method does not return the meta data that the 
    /// property was registered with!!
    /// </remarks>
    public class ScopePropertyMetadata : PropertyMetadata
    {
        /// <summary>
        /// Intercepts <see cref="PropertyChangedCallback"/> events for the property and forwards them to the <see cref="ScopePropertyBehavior"/>
        /// </summary>
        private class PropertyChangedInterceptor
        {
            #region Fields

            private readonly PropertyChangedCallback _propertyChangedCallback;

            #endregion

            public PropertyChangedInterceptor(PropertyChangedCallback propertyChangedCallback)
            {
                _propertyChangedCallback = (sender, e) =>
                    {
                        ScopePropertyBehavior.ValueChanged(sender, e, Metadata);
                        if (propertyChangedCallback != null)
                        {
                            propertyChangedCallback(sender, e);
                        }
                    };
            }

            /// <summary>
            /// Gets or sets the metadata.
            /// </summary>
            /// <value>The metadata.</value>
            public ScopePropertyMetadata Metadata { get; set; }

            /// <summary>
            /// Gets the property changed callback.
            /// </summary>
            /// <value>The property changed callback.</value>
            public PropertyChangedCallback PropertyChangedCallback
            {
                get { return _propertyChangedCallback; }
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ScopePropertyMetadata"/> class.
        /// </summary>
        /// <param name="unsetValue">The unset value.</param>
        public ScopePropertyMetadata(object unsetValue) : this(unsetValue, new PropertyChangedInterceptor(null))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ScopePropertyMetadata"/> class.
        /// </summary>
        /// <param name="unsetValue">The unset value.</param>
        /// <param name="propertyChangedCallback">The property changed callback.</param>
        public ScopePropertyMetadata(object unsetValue, PropertyChangedCallback propertyChangedCallback) : this(unsetValue, 
            new PropertyChangedInterceptor(propertyChangedCallback))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ScopePropertyMetadata"/> class.
        /// </summary>
        /// <param name="unsetValue">The unset value.</param>
        /// <param name="propertyChangedInterceptor">The property changed wrapper.</param>
        private ScopePropertyMetadata(object unsetValue, PropertyChangedInterceptor propertyChangedInterceptor) : base(unsetValue, 
            propertyChangedInterceptor.PropertyChangedCallback)
        {
            // assign meta data
            propertyChangedInterceptor.Metadata = this;
        }

        /// <summary>
        /// Gets the unset value.
        /// </summary>
        /// <value>The unset value.</value>
        public object UnsetValue
        {
            get { return DefaultValue; }
        }
    }
}